package com.mp.approvalreq.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.mp.approvalreq.dao.*;
import com.mp.approvalreq.dao.impl.*;
import com.mp.approvalreq.entity.*;
import com.mp.approvalreq.entity.dto.TemplateDTO;
import com.mp.approvalreq.service.ApprovalDataServiceServant;
import com.mp.approvalreq.util.*;
import com.mp.user.entity.User;
import com.mp.user.service.UserServicePrx;
import com.plusmoney.jdbc.util.DBUtils;
import com.plusmoney.util.DateTimeHelper;
import com.plusmoney.util.Utils;
import com.qq.tars.client.util.ServantUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.sql.Connection;
import java.util.*;
import java.util.stream.Collectors;

public class ApprovalDataServantImpl implements ApprovalDataServiceServant {

    private static final Logger logger = LoggerFactory.getLogger(ApprovalDataServantImpl.class);

    @Override
    public List<TemplateDTO> getAppendSignTemplateUsedInfo(Integer companyId, Integer companyInfoId) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            AppendSignDao appendSignDao = new AppendSignDaoImpl(connection);
            SelectTemplateDao selectTemplateDao = new SelectTemplateDaoImpl(connection);
            UserServicePrx userServicePrx = ServantUtils.getObject(UserServicePrx.class);

            List<TemplateDTO> templates = selectTemplateDao.selectCompanyTemplatesByTemplateType(companyId, Template.APPEND_SIGN);
            if (Utils.isEmpty(templates)) {
                return templates;
            }
            Map<Integer, Integer> appendSignTimesMap = appendSignDao.selectUserAppendSignsTimesMapByMonth(companyId, companyInfoId, DateUtils.getCurrentMonth());
            List<User> userList = userServicePrx.getMultiUserListByCompanyInfoId(companyId, companyInfoId);
            Set<TemplateDTO> templateSet = new HashSet<>();
            for (User user : userList) {
                templateSet.addAll(TemplateUtils.filterTemplatesByUser(user, templates));
            }

            List<TemplateDTO> result = new ArrayList<>();
            for (TemplateDTO dto : templateSet) {
                TemplateDTO template = new TemplateDTO();
                template.setTemplateId(dto.getTemplateId());
                template.setTemplateName(dto.getTemplateName());
                template.setVersion(dto.getVersion());

                template.setMaxTimePermonth(dto.getMaxTimePermonth());
                if (dto.getMaxTimePermonth() != 0) {
                    Integer times = appendSignTimesMap.get(dto.getAncestorId());
                    times = Utils.isNull(times) ? 0 : times;
                    template.setTimesLeftThisMonth((dto.getMaxTimePermonth() - times));
                } else {
                    template.setTimesLeftThisMonth(99999);
                }
                result.add(template);
            }
            return result;
        } catch (Throwable e) {
            logger.error(e.getMessage(), e);
            throw ErrorUtils.throwError(e);
        } finally {
            DBUtils.release(connection);
        }
    }

    @Override
    public List<Integer> getExistOutdoorCompanyIdsByDateScope(String start, String end) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            OutdoorDao outdoorDao = new OutdoorDaoImpl(connection);
            return outdoorDao.selectExistOutdoorCompanyIdsByDateScope(start, end);
        } catch (Throwable e) {
            logger.error(e.getMessage(), e);
            throw ErrorUtils.throwError(e);
        } finally {
            DBUtils.release(connection);
        }
    }

    @Override
    public List<Leave> getLeaves(ApprovalQuery query) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            LeaveDao leaveDao = new LeaveDaoImpl(connection);
            RequestDao requestDao = new RequestDaoImpl(connection);
            String startTime = DateTimeHelper.format(query.getStart(), DateTimeHelper.DEFAULT_PATTERN);
            String endTime = DateTimeHelper.format(query.getEnd(), DateTimeHelper.DEFAULT_PATTERN);

            List<Leave> leaves;
            if (Utils.isEmpty(query.getCompanyInfoIds())) {
                leaves = leaveDao.selectCompanyLeavesByDateScope(query.getCompanyId(), startTime, endTime);
            } else {
                String companyInfoIds = Utils.list2string(query.getCompanyInfoIds());
                leaves = leaveDao.selectBatchUserLeavesByDateScope(query.getCompanyId(), companyInfoIds, startTime, endTime);
            }

            if (Utils.isEmpty(leaves)) {
                return leaves;
            }

            List<Integer> requestIds = LeaveUtils.getRequestIds(leaves);
            List<Request> requests = requestDao.selectRequestByIds(Utils.list2string(requestIds));
            Map<Integer, Request> requestMap = RequestUtils.getRequestMap(requests);

            List<Leave> result = new ArrayList<>();
            for (Leave leave : leaves) {
                if (!requestMap.containsKey(leave.getRequestId())) {
                    continue;
                }
                Request request = requestMap.get(leave.getRequestId());
                if (request.getFinished() == 0 && !Objects.equals(query.getWithUnFinished(), true)) {
                    continue;
                }
                leave.setFinished(request.getFinished());
                result.add(leave);
            }
            return result;
        } catch (Throwable e) {
            logger.error(e.getMessage(), e);
            throw ErrorUtils.throwError(e);
        } finally {
            DBUtils.release(connection);
        }
    }

    @Override
    public List<Outdoor> getOutdoors(ApprovalQuery query) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            OutdoorDao outdoorDao = new OutdoorDaoImpl(connection);
            RequestDao requestDao = new RequestDaoImpl(connection);
            String startTime = DateTimeHelper.format(query.getStart(), DateTimeHelper.DEFAULT_PATTERN);
            String endTime = DateTimeHelper.format(query.getEnd(), DateTimeHelper.DEFAULT_PATTERN);
            List<Outdoor> outdoors;
            if (Utils.isEmpty(query.getCompanyInfoIds())) {
                outdoors = outdoorDao.selectCompanyOutdoorsByDateScope(query.getCompanyId(), startTime, endTime);
            } else {
                String companyInfoIds = Utils.list2string(query.getCompanyInfoIds());
                outdoors = outdoorDao.selectBatchUserOutdoorsByDateScope(query.getCompanyId(), companyInfoIds, startTime, endTime);
            }
            if (Utils.isEmpty(outdoors)) {
                return outdoors;
            }
            List<Integer> requestIds = OutdoorUtils.getRequestIds(outdoors);
            List<Request> requests = requestDao.selectRequestByIds(Utils.list2string(requestIds));
            Map<Integer, Request> requestMap = RequestUtils.getRequestMap(requests);

            for (Outdoor outdoor : outdoors) {
                if (!requestMap.containsKey(outdoor.getRequestId())) {
                    continue;
                }
                Request request = requestMap.get(outdoor.getRequestId());
                outdoor.setFinished(request.getFinished());
            }
            return outdoors;
        } catch (Throwable e) {
            logger.error(e.getMessage(), e);
            throw ErrorUtils.throwError(e);
        } finally {
            DBUtils.release(connection);
        }
    }

    @Override
    public List<AppendSign> getAppendSigns(ApprovalQuery query) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            AppendSignDao appendSignDao = new AppendSignDaoImpl(connection);
            String startTime = DateTimeHelper.format(query.getStart(), DateTimeHelper.DEFAULT_PATTERN);
            String endTime = DateTimeHelper.format(query.getEnd(), DateTimeHelper.DEFAULT_PATTERN);
            List<AppendSign> appendSigns;
            if (Utils.isEmpty(query.getCompanyInfoIds())) {
                appendSigns = appendSignDao.selectCompanyAppendSignsByDateScope(query.getCompanyId(), startTime, endTime);
            } else {
                String companyInfoIds = Utils.list2string(query.getCompanyInfoIds());
                appendSigns = appendSignDao.selectBatchUserAppendSignsByDateScope(query.getCompanyId(), companyInfoIds, startTime, endTime);
            }
            return appendSigns;
        } catch (Throwable e) {
            logger.error(e.getMessage(), e);
            throw ErrorUtils.throwError(e);
        } finally {
            DBUtils.release(connection);
        }
    }

    @Override
    public List<Overtime> getOvertimes(ApprovalQuery query) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            OvertimeDao overtimeDao = new OvertimeDaoImpl(connection);
            RequestDao requestDao = new RequestDaoImpl(connection);
            String startTime = DateTimeHelper.format(query.getStart(), DateTimeHelper.DEFAULT_PATTERN);
            String endTime = DateTimeHelper.format(query.getEnd(), DateTimeHelper.DEFAULT_PATTERN);
            List<Overtime> overtimes;
            if (Utils.isEmpty(query.getCompanyInfoIds())) {
                overtimes = overtimeDao.selectCompanyOvertimesByDateScope(query.getCompanyId(), startTime, endTime);
            } else {
                String companyInfoIds = Utils.list2string(query.getCompanyInfoIds());
                overtimes = overtimeDao.selectBatchUserOvertimesByDateScope(query.getCompanyId(), companyInfoIds, startTime, endTime);
            }
            if (Utils.isEmpty(overtimes)) {
                return overtimes;
            }
            List<Integer> requestIds = OvertimeUtils.getRequestIds(overtimes);
            List<Request> requests = requestDao.selectRequestByIds(Utils.list2string(requestIds));
            Map<Integer, Request> requestMap = RequestUtils.getRequestMap(requests);

            for (Overtime overtime : overtimes) {
                if (!requestMap.containsKey(overtime.getRequestId())) {
                    continue;
                }
                Request request = requestMap.get(overtime.getRequestId());
                overtime.setFinished(request.getFinished());
            }

            return overtimes;
        } catch (Throwable e) {
            logger.error(e.getMessage(), e);
            throw ErrorUtils.throwError(e);
        } finally {
            DBUtils.release(connection);
        }
    }

    @Override
    public List<Data4Cost> getCostDataList(Query query) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            RequestDao requestDao = new RequestDaoImpl(connection);
            ExpenseDao expenseDao = new ExpenseDaoImpl(connection);
            TemplateDao templateDao = new TemplateDaoImpl(connection);
            ComponentDao componentDao = new ComponentImpl(connection);

            List<Request> requests = requestDao.selectNewestRequestByIds(query.getCompanyId(), query.getRequestIds());
            // 过滤掉无效审批
            requests.removeIf(r -> r.getFinished() > 2 || r.getFinished() < 1);
            Map<Integer, Request> requestMap = RequestUtils.getRequestMap(requests);
            List<Template> templates = templateDao.selectTemplateByRequestIds(query.getRequestIds());
            Map<Integer, Template> templateMap = TemplateUtils.getTemplateMap(templates);


            List<Data4Cost> result = new ArrayList<>(requests.size());

            List<Integer> expenseIds = new ArrayList<>(), otherIds = new ArrayList<>();
            for (Request request : requests) {
                switch (request.getDefaultType()) {
                    case Template.EXPENSES:
                    case Template.PURCHASE:
                        expenseIds.add(request.getRequestDkey());
                        break;
                    case Template.OTHER:
                        otherIds.add(request.getRequestDkey());
                        break;
                }
            }
            if (Utils.isNotEmpty(expenseIds)) {
                Map<Integer, List<Expense>> expenseMap = expenseDao.selectExpensesByRequestIds(Utils.list2string(expenseIds));
                for (Map.Entry<Integer, List<Expense>> entry : expenseMap.entrySet()) {
                    Request request = requestMap.get(entry.getKey());
                    Template template = templateMap.get(request.getTemplateId());
                    if (Utils.isNull(template) || !ValidateUtil.isPositiveInteger(template.getRelateAnalysisNum())) {
                        logger.info("不是成本分析模版" + request.getRequestDkey());
                        continue;
                    }
                    Data4Cost data4Cost = new Data4Cost(request);
                    Expense expense = Utils.getFirst(entry.getValue());
                    if (Utils.isNull(expense)) {
                        logger.error("数据异常" + entry.getKey());
                        continue;
                    }
                    data4Cost.setAmount(expense.getTotalAmount());
                    data4Cost.setColor(template.getTemplateColor());
                    Summary summary = SummaryUtils.getExpenseSummary(request, entry.getValue());
                    data4Cost.setContent(summary.getContent());
                    result.add(data4Cost);
                }
            }
            if (Utils.isNotEmpty(otherIds)) {
                Map<Integer, List<TemplateComponent>> componentMap = componentDao.selectComponentMapByRequestIds(Utils.list2string(otherIds));
                Map<Integer, Map<Integer, List<GroupContent>>> groupComponentMap = componentDao.selectGroupComponentByRequestIds(Utils.list2string(otherIds));

                for (Integer id : otherIds) {
                    Request request = requestMap.get(id);
                    Template template = templateMap.get(request.getTemplateId());
                    if (Utils.isNull(template) || !ValidateUtil.isPositiveInteger(template.getRelateAnalysisNum())) {
                        logger.info("不是成本分析模版" + id);
                        continue;
                    }
                    int num = Integer.parseInt(template.getRelateAnalysisNum());
                    List<TemplateComponent> components = componentMap.get(id);
                    TemplateComponent component = components.stream().filter(c -> c.getNum() == num).findFirst().orElse(null);
                    if (Utils.isNull(component) || !ValidateUtil.isNumber(component.getValue())) {
                        logger.error("查不到相关组件" + id);
                        continue;
                    }
                    Data4Cost data4Cost = new Data4Cost(request);
                    data4Cost.setColor(template.getTemplateColor());
                    data4Cost.setAmount(new BigDecimal(component.getValue()).setScale(2, RoundingMode.HALF_UP));
                    List<TemplateComponent> componentsContent = componentMap.get(request.getRequestDkey());
                    Map<Integer, List<GroupContent>> groupContentMap = groupComponentMap.get(request.getRequestDkey());
                    if (Utils.isNotEmpty(groupContentMap)) {
                        for (TemplateComponent templateComponent : componentsContent) {
                            if (groupContentMap.containsKey(templateComponent.getNum())) {
                                templateComponent.setGroupContents(groupContentMap.get(templateComponent.getNum()));
                                break;
                            }
                        }
                    }
                    request.setComponentsContent(componentsContent);
                    Summary summary = SummaryUtils.getOtherSignSummary(request);
                    data4Cost.setContent(summary.getContent());
                    result.add(data4Cost);
                }
            }
            return result;
        } catch (Throwable e) {
            logger.error(e.getMessage(), e);
            throw ErrorUtils.throwError(e);
        } finally {
            DBUtils.release(connection);
        }
    }

    @Override
    public List<Approval2Amoeba> getDataForAmoeba(List<Integer> contactIds, String param, String month) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            TemplateDao templateDao = new TemplateDaoImpl(connection);
            RequestDao requestDao = new RequestDaoImpl(connection);
            ComponentDao componentDao = new ComponentImpl(connection);

            UserServicePrx userServicePrx = ServantUtils.getObject(UserServicePrx.class);
            TemplateComponent component = JSONObject.parseObject(param, TemplateComponent.class);
            List<Approval2Amoeba> results = new ArrayList<>();

            List<Template> templates = templateDao.selectTemplatesByAncestorId(component.getTemplateAncestorId());
            if (Utils.isEmpty(templates)) {
                return results;
            }
            Map<Integer, Template> templateMap = templates.stream().collect(Collectors.toMap(Template::getTemplateId, t -> t, (a, b) -> a));
            Map<Integer, Integer> numMap = matchNum(component, templates);
            logger.info("numMap:{}", numMap);

            for (Integer contactId : contactIds) {
                User user = userServicePrx.getUserByContactId(contactId);

                List<Request> requests = requestDao.selectUserRequestByTemplateIds(user.getCompanyId(), user.getContactId(), month, Utils.collection2string(templateMap.keySet()));
                if (Utils.isEmpty(requests)) {
                    continue;
                }
                Map<Integer, Request> requestMap = RequestUtils.getRequestMap(requests);
                Map<Integer, List<TemplateComponent>> componentMap = componentDao.selectComponentMapByRequestIds(Utils.collection2string(requestMap.keySet()));

                for (List<TemplateComponent> components : componentMap.values()) {
                    Map<Integer, String> valueMap = ComponentUtils.getComponentValueMap(components);
                    Request request = requestMap.get(components.get(0).getRequestId());
                    String value = valueMap.get(numMap.get(request.getTemplateId()));
                    if (!ValidateUtil.isDouble(value)) {
                        continue;
                    }
                    Approval2Amoeba data = new Approval2Amoeba();
                    data.setContactId(user.getContactId());
                    data.setCompanyInfoId(user.getCompanyInfoId());
                    data.setRequestId(request.getRequestDkey());
                    data.setValue(new BigDecimal(value).setScale(2, RoundingMode.HALF_UP));
                    data.setCreateTime(request.getCreateTimestamp());
                    results.add(data);
                }
            }


            return results;
        } catch (Throwable e) {
            logger.error(e.getMessage(), e);
            throw ErrorUtils.throwError(e);
        } finally {
            DBUtils.release(connection);
        }
    }

    private Map<Integer, Integer> matchNum(TemplateComponent com, List<Template> templates) {
        Map<Integer, Integer> map = new HashMap<>();
        for (Template template : templates) {
            List<TemplateComponent> components = JSONObject.parseArray(template.getTemplateComponent(), TemplateComponent.class);
            List<TemplateComponent> results = components.stream().filter(c -> Objects.equals(c.getType(), com.getType()) && Objects.equals(c.getName(), com.getName())
                    && Objects.equals(c.getNum(), com.getNum())).collect(Collectors.toList());
            if (Utils.isNotEmpty(results)) {
                map.put(template.getTemplateId(), results.get(0).getNum());
                continue;
            }

            // 调整了组件信息
            for (TemplateComponent component : components) {
                if (!component.getType().equals(com.getType())) {
                    continue;
                }
                // 名字没改,位置改了
                if (Objects.equals(component.getName(), com.getName())) {
                    map.put(template.getTemplateId(), component.getNum());
                    continue;
                }
                // 位置改了,名字没改
                if (Objects.equals(component.getNum(), com.getNum())) {
                    map.put(template.getTemplateId(), component.getNum());
                }
            }
        }
        return map;
    }

    @Override
    public Outdoor getOutdoor(Integer requestId) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            OutdoorDao outdoorDao = new OutdoorDaoImpl(connection);
            return outdoorDao.selectLastOutdoorByRequestId(requestId);
        } catch (Throwable e) {
            logger.error(e.getMessage(), e);
            throw ErrorUtils.throwError(e);
        } finally {
            DBUtils.release(connection);
        }
    }
}
